package org.dev.vlp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.dev.vlp.constants.EnumLikeTargetType;
import org.dev.vlp.constants.EnumNotificationCategory;
import org.dev.vlp.constants.EnumNotificationType;
import org.dev.vlp.constants.HtmlTemplateConstant;
import org.dev.vlp.dto.GroupCountDTO;
import org.dev.vlp.dto.PublishCommentParam;
import org.dev.vlp.entity.*;
import org.dev.vlp.exception.ApiException;
import org.dev.vlp.mapper.*;
import org.dev.vlp.service.CommentService;
import org.dev.vlp.service.NotificationService;
import org.dev.vlp.utils.AssertUtils;
import org.dev.vlp.utils.PageResult;
import org.dev.vlp.utils.PageUtils;
import org.dev.vlp.utils.ReplaceUtils;
import org.dev.vlp.vo.CommentVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* @author 86184
* @description 针对表【vlp_comment(评论表)】的数据库操作Service实现
* @createDate 2023-01-12 14:11:04
*/
@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment>
    implements CommentService{

    @Autowired
    private MomentMapper momentMapper;

    @Autowired
    private CommentMapper commentMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private NotificationService notificationService;

    @Autowired
    private NotificationMapper notificationMapper;
    @Autowired
    private LikeRelationMapper likeRelationMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void publishComment(PublishCommentParam publishCommentParam,int userId) {

        // 查询用户是否加入该贴的社区，如果没有就需要先加入社区才能回复
        int momentId = publishCommentParam.getMomentId();
        int parentId = publishCommentParam.getParentId();
        int replyToId = publishCommentParam.getReplyToId();
        String content = publishCommentParam.getContent();

        Moment momentDBO = momentMapper.selectById(momentId);
        AssertUtils.notNull(momentDBO, "moment不存在：" + momentId);
        Comment parent=null;
        Comment reply=null;

        if (!Objects.equals(parentId, 0)) {
            // 子评论
            parent = commentMapper.selectById(parentId);
            if (parent==null) {
                throw new ApiException("父评论不存在");
            }
        }
        if (!Objects.equals(replyToId, 0)) {
            // 子评论中回复某人
            reply = commentMapper.selectById(replyToId);
            if (reply==null) {
                throw new ApiException("回复的评论不存在");
            }
        }

        // 处理文本
        Set<Long> atUserIdList = new HashSet<>();
        String newTextContent = handlePublishMomentTextContent(content, atUserIdList);

        // 插入评论
        Comment commentDBO = new Comment();
        commentDBO.setUserId((long) userId);
        commentDBO.setMomentId((long) momentId);
        commentDBO.setContent(newTextContent);
        commentDBO.setParentId((long) parentId);
        commentDBO.setReplyToId(Objects.equals(parentId, 0) ? 0L : replyToId);
        commentMapper.insert(commentDBO);
        momentMapper.updateCommentCount((long) momentId, 1);

        // @用户 发消息
        if (CollectionUtils.isNotEmpty(atUserIdList)) {
            // 动态评论
            if (Objects.equals(commentDBO.getParentId(), 0L)) {
                atUserIdList.forEach(atUserId -> {
                    notificationService.sendNotification(Notification.builder()
                            .type(EnumNotificationType.AT_ON_COMMENT.getValue())
                            .momentId((long) momentId)
                            .commentId(commentDBO.getCommentId())
                            .receiveUserId(atUserId)
                            .build(),userId);
                });
            } else {
            //  动态评论的评论
                atUserIdList.forEach(atUserId -> {
                    notificationService.sendNotification(Notification.builder()
                            .type(EnumNotificationType.AT_ON_CHILDREN_COMMENT.getValue())
                            .momentId((long) momentId)
                            .parentCommentId(commentDBO.getParentId())
                            .commentId(commentDBO.getCommentId())
                            .receiveUserId(atUserId)
                            .build(),userId);
                });
            }
        }

        // 发消息
        if (Objects.equals(commentDBO.getParentId(), 0L)) {
            notificationService.sendNotification(Notification.builder()
                    .type(EnumNotificationType.COMMENT_TO_MOMENT.getValue())
                    .momentId((long) momentId)
                    .commentId(commentDBO.getCommentId())
                    .receiveUserId(momentDBO.getUserId())
                    .build(),userId);
        } else {
            notificationService.sendNotification(Notification.builder()
                    .type(EnumNotificationType.REPLY_TO_MOMENT_COMMENT.getValue())
                    .momentId((long) momentId)
                    .parentCommentId(commentDBO.getParentId())
                    .commentId(commentDBO.getCommentId())
                    .receiveUserId(parent.getUserId())
                    .build(),userId);
        }

    }

    private String handlePublishMomentTextContent(String textContent, Set<Long> atUserIdList) {
        // 处理@
        Set<String> matchedAtSet = new HashSet<>();
        Set<String> newMatchedAtSet = new HashSet<>();
        textContent = ReplaceUtils.translate(textContent, HtmlTemplateConstant.AT_TEMPLATE, HtmlTemplateConstant.AT_PATTERN, new HashMap<>(), matchedAtSet);
        matchedAtSet.forEach(userName -> {
            if (userName.length() > 1) {
                String newUserName = userName.substring(1);
                newMatchedAtSet.add(newUserName);
            }
        });
        if (CollectionUtils.isNotEmpty(newMatchedAtSet)) {
            QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
            userQueryWrapper.in("username",newMatchedAtSet);
            List<User> userDBOList = userMapper.selectList(userQueryWrapper);
            if (CollectionUtils.isNotEmpty(userDBOList)) {
                atUserIdList.addAll(userDBOList.stream().map(User::getUserId).collect(Collectors.toSet()));
            }
        }
        return textContent;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteComment(long commentId, int userId) {
        Comment commentDBO = commentMapper.selectById(commentId);
        AssertUtils.notNull(commentDBO, "comment不存在：" + commentId);

        if(commentDBO.getUserId()!=userId){
            throw new ApiException("无权限删除");
        }
        commentDBO.setIsDeleted(1);
        commentMapper.updateById(commentDBO);

        // 取消消息中心回复信息
        QueryWrapper<Notification> notificationQueryWrapper = new QueryWrapper<>();
        notificationQueryWrapper.eq("send_user_id",userId)
                .eq("category", EnumNotificationCategory.COMMENT.getValue())
                .eq("comment_id",commentId);
        Notification notification = notificationMapper.selectOne(notificationQueryWrapper);
        notification.setIsDeleted(1);
        notificationMapper.updateById(notification);
        momentMapper.updateCommentCount(commentDBO.getMomentId(), -1);
    }

    @Override
    public PageResult queryMomentComment(Long momentId, int page, int size,int userId,int parentId) {

        // 查询评论
        int start = PageUtils.getStart(page, size);
        List<CommentVo> commentDTOList = commentMapper.getMomentComment(start, size, momentId.intValue(),parentId);
        QueryWrapper<Comment> commentQueryWrapper = new QueryWrapper<>();
        commentQueryWrapper.eq("moment_id",momentId).eq("parent_id",parentId).eq("is_deleted",0);
        Long aLong = commentMapper.selectCount(commentQueryWrapper);
        if (CollectionUtils.isEmpty(commentDTOList)) {
            return new PageResult(commentDTOList,aLong,size);
        }

        // 绑定点赞信息
        bindCommentExtraInfo((long) userId, commentDTOList);

        if (!Objects.equals(parentId, 0L)) {
            Set<Long> replyToCommentIdSet = commentDTOList.stream().map(CommentVo::getReplyToId).filter(x -> !Objects.equals(x, 0L)).collect(Collectors.toSet());
            if (CollectionUtils.isNotEmpty(replyToCommentIdSet)) {
                List<CommentVo> replyToCommentDTOList =commentMapper.queryCommentIds(new ArrayList<>(replyToCommentIdSet));
                if (CollectionUtils.isNotEmpty(replyToCommentDTOList)) {
                    bindCommentExtraInfo((long) userId, replyToCommentDTOList);
                }

                Map<Long, CommentVo> idToComment = replyToCommentDTOList.stream().collect(Collectors.toMap(CommentVo::getCommentId, Function.identity(), (key1, key2) -> key2));
                commentDTOList.forEach(commentDTO -> {
                    Long replyToId = commentDTO.getReplyToId();
                    if (!Objects.equals(replyToId, 0L)) {
                        commentDTO.setReplyToComment(idToComment.get(replyToId));
                    }
                });
            }
        }

        return new PageResult(commentDTOList,aLong,size);
    }

    private void bindCommentExtraInfo(Long userId, List<CommentVo> commentDTOList) {

        if (CollectionUtils.isEmpty(commentDTOList)) {
            return;
        }
        // 是否点赞
        List<Long> commentIdList = commentDTOList.stream().map(CommentVo::getCommentId).collect(Collectors.toList());
        QueryWrapper<LikeRelation> likeRelationQueryWrapper = new QueryWrapper<>();
        likeRelationQueryWrapper.eq("user_id",userId)
                .eq("type",EnumLikeTargetType.COMMENT.getValue())
                .in("target_id",commentIdList);
        List<LikeRelation> likeRelationDBOList = likeRelationMapper.selectList(likeRelationQueryWrapper);
//        List<LikeRelation> likeRelationDBOList = likeRelationMapper.queryByUserTargetTypeTargetIds(userId, EnumLikeTargetType.COMMENT.getValue(), commentIdList);
        Map<Long, LikeRelation> commentIdToLikeRelation = likeRelationDBOList.stream().collect(Collectors.toMap(LikeRelation::getTargetId, Function.identity(), (key1, key2) -> key2));
        commentDTOList.forEach(comment -> {
            comment.setHasLiked(commentIdToLikeRelation.get(comment.getCommentId()) != null);
        });
    }




}




